/**
 * Copyright (c) 2006, PORTALIER Julien
 * 
 * Licensed under The LGPL License
 * Redistributions of files must retain the above copyright notice.
 * 
 * @package    Feather-CM
 * @subpackage Javascript
 * @copyright  Copyright (c) 2006, Julien PORTALIER
 * @link       http://portalier.com/feather
 * @license    http://www.opensource.org/licenses/lgpl-license.php The LGPL License
 */

var Autocompleter = {};

Autocompleter.Base = new Class(
{
	initialize: function(input, choices, url, options)
	{
		this.url      = url;
		this.tokens   = [];
		this.token    = undefined;
		this.index    = 0;
		this.doSearch = true;
		
		this.options = Object.extend({
			minChars:  1,
			tokenMark: ',',
			delay:     500,
			paramName: 'value'
		}, options || {});
		
		// elements
		this.input = $(input);
		this.input.setAttribute('autocompleter', 'off');
		this.choices = $(choices).hide();
		
		// IE reports Up/Down keys with keydown;
		// All browsers report the Return key with keypress.
		this.input.addEvent('keydown',  this.onKeyDown.bindWithEvent(this));
		this.input.addEvent('keypress', this.onKeyPress.bindWithEvent(this));
		this.input.addEvent('blur',     this.clean.bind(this));
		
		this.choices.addEvent('mouseover', this.onMouseOver.bindWithEvent(this));
		this.choices.addEvent('mousedown', this.onChoice.bind(this));
	},
	
	clean: function()
	{
		this.choices.hide();
		this.tokens = [];
		this.token  = undefined;
		this.index  = 0;
	},
	
	// requests
	
	search: function()
	{
		this.getToken();
		if (this.token.length >= this.options.minChars && !(/^\s*$/.test(this.token)))
		{
			if (this.ajax)
				this.ajax.abort();
			
			var url = this.url;
			if (this.options.paramName)
				url += '?' + this.options.paramName + '=';
			this.ajax = new Ajax(url + encodeURIComponent(this.token), {
				method: 'get',
				onComplete: this.afterSearch.bind(this),
				onFailure:  this.onFailure.bind(this)
			}).request();
		}
	},
	
	afterSearch: function(html)
	{
		// updates choices
		this.choices.innerHTML = html;
		
		// checks for any results
		var tokens = $ES('li', this.choices);
		if (tokens.length > 0)
		{
			var index   = 0;
			this.tokens = [];
			tokens.each(function(li)
			{
				this.tokens.push(li.innerHTML);
				li.index = index;
				index++;
			}, this);
			
			this.index = 0;
			this.selectChoice();
		}
		else {
			this.tokens = [];
		}
		
		// any results? let's display choices
		if (this.tokens.length)
			this.choices.show();
		
		this.ajax = null;
	},
	
	onFailure: function(response)
	{
		alert(_("An error occured:") + ' ' + response);
	},
	
	// events
	
	onKeyPress: function(evt)
	{
		if (evt.code == Event.keys.enter)
		{
			this.onChoice();
			evt.stop();
		}
	},
	
	onKeyDown: function(evt)
	{
		this.specialKeys = this.specialKeys || [
			Event.keys.left,
			Event.keys.right,
			Event.keys.enter,
			Event.keys.tag,
			/*Event.keys.delete,*/ 46,
			Event.keys.backspace
		];
		
		switch(evt.code)
		{
			case Event.keys.down:
				this.index = Math.min(this.index + 1, this.tokens.length - 1);
				this.selectChoice();
				evt.stop();
				return;
			
			case Event.keys.up:
				this.index = Math.max(this.index - 1, 0);
				this.selectChoice();
				evt.stop();
				return;
			
			case Event.keys.esc:
				this.clean();
				this.doSearch = false;
				evt.stop();
				return;
			
			default:
				this.doSearch = true;
		}
		
		if (this.doSearch && !this.specialKeys.test(evt.code))
		{
			$clear(this.fetchTimer);
			this.fetchTimer = this.search.delay(this.options.delay, this);
		}
	},
	
	onMouseOver: function(evt)
	{
		this.index = evt.target.index;
		this.selectChoice();
	},
	
	// choices
	
	selectChoice: function()
	{
		var choices = $ES('li', this.choices);
		var el = choices[this.index];
		if (el && !el.hasClass('selected'))
		{
			choices.each(function(li) { li.removeClass('selected'); });
			el.addClass('selected');
		}
	},
	
	onChoice: function()
	{
		this.setToken();
		this.clean();
	},
	
	// tokens
	
	getToken: function()
	{
		this.token = (this.input.value.indexOf(this.options.tokenMark) > -1) ?
			this.input.value.split(this.options.tokenMark).pop() : this.input.value;
		this.token = this.token.trim();
	},
	
	setToken: function()
	{
		var token = this.tokens[this.index];
		if (!token)
			return;
		
		if (this.input.value.indexOf(this.options.tokenMark) > -1)
		{
			var tokens = this.input.value.split(this.options.tokenMark);
			for (var i = 0; i < tokens.length - 1; i++)
				tokens[i] = tokens[i].trim();
			tokens.pop();
			tokens.push(token);
			this.input.value = tokens.join(', ');
		}
		else {
			this.input.value = token;
		}
		this.input.value += ', ';
	}
});